home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / BG_SRC.ZIP / BG_GRAF2.C < prev    next >
C/C++ Source or Header  |  1993-02-05  |  22KB  |  662 lines

  1. /*
  2.  *                     B  G  _  G  R  A  F  2  .  C
  3.  *         A graphics module for the backgammon playing program BG.C.
  4.  * This version  14th January 1993
  5.  *
  6.  
  7. The computer idea of the graphics of the board is based on BLACK where
  8. the two runners of black are at the top left, i.e the initial position is:
  9.    0    1  2  3  4  5  6   7   8  9 10 11 12 13   <-- grid col
  10.    25   1  2  3  4  5  6   0   7  8  9 10 11 12   <-- index in layout
  11.    H    B              W   |      W           B   0
  12.         B  whites      W   |      W           B   1
  13.    O       inner       W   |      W           B   2
  14.            table       W   B                  B   3
  15.    M                   W   |                  B   4
  16.         -------------------A-------------------   5,6
  17.    E                   B   |                  W   7
  18.            blacks      B   R                  W   8
  19.            inner       B   |      B           W   9
  20.         W  table       B   |      B           W   10
  21.         W              B   |      B           W   11
  22.    25  24 23 22 21 20 19   0  18 17 16 15 14 13   <-- index in layout
  23.  
  24. The pieces are on a grid of GRID_ROWS by GRID_COLS. See also comments
  25. in BG_GRAF1.C. We use the above numbering system, BLACK going home means
  26. increasing indices.
  27. *************************************************************************/
  28.  
  29. #include "comp.h"
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <bios.h>
  33. #include <conio.h>
  34. #include "mousy.h"
  35. #include "bg.h"
  36.  
  37. /*************************************************************************/
  38.  
  39. extern Screen_Const_t Grafs ;
  40. extern Disp_Cfg_t Disp_Cfg ;
  41.  
  42. /* Private function prototypes */
  43.  
  44. static void Get_Grid_Point_Top (short* Grid_Col, short* Grid_Row,
  45.                                 Player_t Player, short Point_Num) ;
  46. static void Get_Grid_Point (short* Grid_Col, short* Grid_Row,
  47.                             Player_t Player, short Point_Num,
  48.                             short Piece_Row) ;
  49. static void Draw_Point_Triangle (Player_t Player, short Point_Num) ;
  50. static void Draw_Point_And_Pieces (Player_t Plyr, short Num, char n) ;
  51. static void Draw_Pieces (Player_t Player, short Num, char n) ;
  52. static void Draw_Piece (short x, short y, Player_t Player) ;
  53.  
  54. /*************************************************************************/
  55.  
  56. void Get_Pbox_Coords (short    Box_Coords[2][2],
  57.                       Player_t Player, short Point_Num)
  58. /*
  59. PURPOSE: To return the opposite corners of the box which is at Point_Num.
  60. NOTES  : 1) The returned coords include pixels you can draw on top of.
  61.          2) A very important idea is represented by this function, i.e.
  62.          that of an area within which you can draw. If you go out of
  63.          this area you may destroy parts of dividing lines or text areas.
  64. */
  65. {
  66.     short Row0,Col0,Row1,Col1 ;
  67.  
  68.     Get_Grid_Point_Top (&Col0,&Row0,Player,Point_Num) ;
  69.     /* Get the grid square at opposite corner (bottom right) */
  70.     Col1 = Col0 + 1 ;
  71.     Row1 = Row0 + (GRID_ROWS/2) ;
  72.  
  73.     Get_Grid_Corner (&Box_Coords[0][XI],&Box_Coords[0][YI],Col0,Row0) ;
  74.     Get_Grid_Corner (&Box_Coords[1][XI],&Box_Coords[1][YI],Col1,Row1) ;
  75.     Box_Coords [0][XI]++ ;
  76.     Box_Coords [0][YI]++ ;
  77.     Box_Coords [1][XI]-- ;
  78.     Box_Coords [1][YI]-- ;
  79. }
  80.  
  81. /***************************************************************************/
  82.  
  83. #define ODD(a) (((a/2)*2) != a)
  84.  
  85. static void Draw_Point_Triangle (Player_t Player, short Point_Num)
  86. /*
  87. PURPOSE: To draw the triangle of the players point, erasing what was
  88.          there before.
  89. NOTES:   The triangle will be either of the following:
  90.                 0                  1 2
  91.                1 2                  0
  92.              upwards             downwards
  93. */
  94. {
  95.     short A_Box [2][2] ; /* Defines box of the point */
  96.     short Mid_X ;        /* X coord of the tip of the triangle */
  97.     short Trig[6] ;      /* The triangle we create then draw */
  98.     short Point_Colour ;
  99.  
  100.     Get_Pbox_Coords (A_Box,Player,Point_Num) ;
  101.  
  102.     Clear_Point (Player,Point_Num) ;
  103.     Mid_X = (A_Box[0][XI] + A_Box[1][XI]) / 2 ;
  104.     if (!Disp_Cfg.Colour) {
  105.         Point_Colour = WHITE ;
  106.     } else if ((EVEN(Point_Num) && (Player == BLACK_PLAYER)) ||
  107.                (ODD(Point_Num)  && (Player == WHITE_PLAYER))) {
  108.         Point_Colour = RED ;
  109.     } else {
  110.         Point_Colour = GREEN ;
  111.     }
  112.     if (((Player == BLACK_PLAYER) && (Point_Num >= 13)) ||
  113.         ((Player == WHITE_PLAYER) && (Point_Num <= 12))) {
  114.         /* An upward pointing triangle */
  115.         Trig [0] = Mid_X ;
  116.         Trig [1] = A_Box[0][YI] ;
  117.         Trig [2] = A_Box[0][XI] ;
  118.         Trig [3] = A_Box[1][YI] ;
  119.         Trig [4] = A_Box[1][XI] ;
  120.         Trig [5] = A_Box[1][YI] ;
  121.     } else {
  122.         /* A downwards pointing triangle */
  123.         Trig [0] = Mid_X ;
  124.         Trig [1] = A_Box[1][YI] ;
  125.         Trig [2] = A_Box[0][XI] ;
  126.         Trig [3] = A_Box[0][YI] ;
  127.         Trig [4] = A_Box[1][XI] ;
  128.         Trig [5] = A_Box[0][YI] ;
  129.     }
  130.  
  131.     if (Disp_Cfg.Colour) {
  132.         Fill_Poly (3,Trig,Point_Colour) ;
  133.     } else {
  134.         short i,c1,c2 ;
  135.         for (i = 0 ; i < 3 ; i++) {
  136.             c1 = i * 2  ;
  137.             c2 = ((i + 1) % 3) * 2  ;
  138.             Draw_Line (Trig[c1],Trig[c1+1],
  139.                        Trig[c2],Trig[c2+1],WHITE) ;
  140.         }
  141.     }
  142. }
  143.  
  144. /***************************************************************************/
  145.  
  146. static void Draw_Point_And_Pieces (Player_t Player, short Point_Num, char N_Pieces)
  147. /*
  148. PURPOSE: To draw the point and the pieces of the player on the point.
  149. */
  150. {
  151.     if ((Point_Num == HOME_I) || (Point_Num == BAR_I)) {
  152.         Clear_Point (Player,Point_Num) ;
  153.     } else {
  154.         Draw_Point_Triangle (Player,Point_Num) ;
  155.     }
  156.     Draw_Pieces (Player,Point_Num,N_Pieces) ;
  157. }
  158.  
  159. /***************************************************************************/
  160.  
  161. static void Draw_Pieces (Player_t Player, short Point_Num, char N_Pieces)
  162. /*
  163. PURPOSE: To draw the pieces of the player on the point.
  164. NOTES  : 1) If there are Rows_Available pieces or less we are
  165.          ok and all pieces will fit on the triangle, otherwise
  166.          we have to do some fancy footwork, overlapping them.
  167.          2) Here we should reverse the doodahs when doing the bar.
  168. */
  169. {
  170.     short X_Center,Y_Center,Nth_Row,Rows_Available ;
  171.  
  172.     Nth_Row = 0 ;
  173.     if (Point_Num == BAR_I) {
  174.         /* Leave space for T and D cells in center of bar, plus
  175.         doubling cube at bottom or top */
  176.         Rows_Available = (GRID_ROWS/2) - 2 ;
  177.     } else {
  178.         Rows_Available = GRID_ROWS/2 ;
  179.     }
  180.     while (Nth_Row < N_Pieces)  {
  181.         Get_Piece_Center (&X_Center,&Y_Center,Player,Point_Num,Nth_Row,
  182.                           N_Pieces,Rows_Available) ;
  183.         Draw_Piece (X_Center,Y_Center,Player) ;
  184.         Nth_Row ++ ;
  185.     }
  186. }
  187.  
  188. /***************************************************************************/
  189.  
  190. static void Draw_Piece (short x, short y, Player_t Player)
  191. /*
  192. PURPOSE: To draw a piece centred on x,y.
  193. */
  194. {
  195.     if (Disp_Cfg.Colour) {
  196.         if (Player == BLACK_PLAYER) {
  197.             Fill_Ellipse (x,y,Grafs.Unit_Wide/2,Grafs.Unit_High/2,LIGHTRED) ;
  198.             Draw_Ellipse (x,y,Grafs.Unit_Wide/2,Grafs.Unit_High/2,WHITE) ;
  199.         } else {
  200.             Fill_Ellipse (x,y,Grafs.Unit_Wide/2,Grafs.Unit_High/2,WHITE) ;
  201.             Draw_Ellipse (x,y,Grafs.Unit_Wide/2,Grafs.Unit_High/2,BLACK) ;
  202.         }
  203.     } else {
  204.         if (Player == BLACK_PLAYER) {
  205.             Draw_Ellipse (x,y,Grafs.Unit_Wide/2,Grafs.Unit_High/2,WHITE) ;
  206.         } else {
  207.             Fill_Ellipse (x,y,Grafs.Unit_Wide/2,Grafs.Unit_High/2,WHITE) ;
  208.         }
  209.     }
  210. }
  211.  
  212. /***************************************************************************/
  213.  
  214. static void Get_Grid_Point_Top (short* Grid_Col, short* Grid_Row,
  215.                                 Player_t Player, short Point_Num)
  216. /*
  217. PURPOSE: Given the point number for the player return the grid row and
  218.          column of the grid box closest to the top of the board, see
  219.          diagram at the top of this file.
  220. NOTES:   1) The home and bar 'points' (areas) are also valid
  221. */
  222. {
  223.     short Row,Col ;
  224.     boolean Col_Done ;
  225.  
  226.     if (Point_Num == BAR_I) {
  227.         Col      = BAR_COL ;
  228.         Col_Done = TRUE ;
  229.     } else if (Point_Num == HOME_I) {
  230.         Col      = HOME_COL ;
  231.         Col_Done = TRUE ;
  232.     } else {
  233.         Col_Done = FALSE ;
  234.     }
  235.  
  236.     if (Player == WHITE_PLAYER) {
  237.         /* We work always with black */
  238.         Point_Num = Reverse_Index (Point_Num) ;
  239.     }
  240.     if (Point_Num >= 13) {
  241.         /* We are in the lower half of the board */
  242.         if (!Col_Done) {
  243.             Col = 25 - Point_Num ;
  244.         }
  245.         Row = GRID_ROWS/2  ;
  246.     } else {
  247.         /* We are in the upper half */
  248.         if (!Col_Done) {
  249.             Col = Point_Num ;
  250.         }
  251.         Row = 0 ;
  252.     }
  253.     if ((Col > 6) && (!Col_Done)) {
  254.         Col++ ; /* Skip the area of the bar */
  255.     }
  256.     *Grid_Col = Col ;
  257.     *Grid_Row = Row ;
  258. }
  259.  
  260. /***************************************************************************/
  261.  
  262. static void Get_Grid_Point (short* Grid_Col, short* Grid_Row,
  263.                             Player_t Player, short Point_Num,
  264.                             short Piece_Row)
  265. /*
  266. PURPOSE: Given the Player, the Point_Num, and the Piece_Row (how far
  267.          the piece is from the edge of the board) we return the Grid
  268.          row and column. This means of course that as Piece_Row gets
  269.          higher we get closer to the vertical center of the board.
  270. NOTES:   1) This function does NOT 'squash' the pieces if there are
  271.          too many of them in a column.
  272. */
  273. {
  274.     short   Row,Col ;
  275.  
  276.     if (Point_Num != BAR_I) {
  277.         boolean Col_Done ;
  278.  
  279.         if (Point_Num == HOME_I) {
  280.             Col      = HOME_COL ;
  281.             Col_Done = TRUE ;
  282.         } else {
  283.             Col_Done = FALSE ;
  284.         }
  285.         if (Player == WHITE_PLAYER) {
  286.             /* We work always with black */
  287.             Point_Num = Reverse_Index (Point_Num) ;
  288.         }
  289.         if (Point_Num >= 13) {
  290.             /* We are in the lower half of the board */
  291.             if (!Col_Done) {
  292.                 Col = 25 - Point_Num ;
  293.             }
  294.             Row = (GRID_ROWS-1) - Piece_Row  ;
  295.         } else {
  296.             /* We are in the upper half */
  297.             if (!Col_Done) {
  298.                 Col = Point_Num ;
  299.             }
  300.             Row = Piece_Row ;
  301.         }
  302.         if ((Col > 6) && (!Col_Done)) {
  303.             Col++ ; /* Skip the area of the bar */
  304.         }
  305.  
  306.     } else {
  307.         /* On the BAR, we need to work from center outwards, leaving
  308.         two cells in the center for the doubling cube button */
  309.         Col = BAR_COL ;
  310.         Piece_Row ++ ; /* Leave a bit of space in center */
  311.         if (Player == WHITE_PLAYER) {
  312.             Row = (GRID_ROWS/2) + Piece_Row ;
  313.         } else {
  314.             Row = ((GRID_ROWS/2)-1) - Piece_Row ;
  315.         }
  316.     }
  317.     *Grid_Col = Col ;
  318.     *Grid_Row = Row ;
  319. }
  320.  
  321. /***************************************************************************/
  322.  
  323. static Layout_t Start_Graf_Layout = {20,
  324.                                      20,20,20,20,20,20,
  325.                                      20,20,20,20,20,20,
  326.                                      20,20,20,20,20,20,
  327.                                      20,20,20,20,20,20,
  328.                                      20} ;
  329.  
  330. /* 'Old' layouts initialised  to this pattern when you want */
  331. /* to force a full redraw, see below    */
  332.  
  333. /****************************************************************************/
  334.  
  335. Layout_t Old_Black, Old_White ; /* What we drew before */
  336.  
  337. void Draw_Board_Full (Layout_t Lays[N_PLAYERS])
  338. /*
  339. PURPOSE: To update the board fully, drawing all points.
  340. */
  341. {
  342.     extern boolean  No_Cube ;
  343.     short p,x,y ;
  344.     short A_Box [2][2] ; /* Defines box of the point */
  345.  
  346.     /* Erase the previous board */
  347.     Fill_Rect (0,0,Grafs.Board_Wide,Grafs.Board_High,BLACK) ;
  348.     /* Draw edge of the board */
  349.     Draw_Rect (0,0,Grafs.Board_Wide+2,Grafs.Board_High+2,WHITE) ;
  350.     /* Since the board has Board_Wide pixels the frame must be 2 pixels
  351.     bigger */
  352.  
  353.     /* Draw the home line */
  354.     Get_Grid_Corner (&x,&y,HOME_COL+1,0) ;
  355.     Draw_Line (x,y,x,y+Grafs.Board_High-1,WHITE) ;
  356.  
  357.     /* Draw the bar lines
  358.     Get_Grid_Corner (&x,&y,BAR_COL,0) ;
  359.     Draw_Line (x,y,x,y+Grafs.Board_High-1,WHITE) ;
  360.     Get_Grid_Corner (&x,&y,BAR_COL+1,0) ;
  361.     Draw_Line (x,y,x,y+Grafs.Board_High-1,WHITE) ; */
  362.  
  363.     Get_Pbox_Coords (A_Box,BLACK_PLAYER,BAR_I) ;
  364.     Draw_Line (A_Box[0][XI]-1,A_Box[0][YI]-1,
  365.                A_Box[0][XI]-1,A_Box[0][YI]-1+Grafs.Board_High-1,
  366.                WHITE) ;
  367.     Draw_Line (A_Box[1][XI]+1,A_Box[0][YI]-1,
  368.                A_Box[1][XI]+1,A_Box[0][YI]-1+Grafs.Board_High-1,
  369.                WHITE) ;
  370.  
  371.     for (p=0 ; p < N_PLACES ; p++) {
  372.         Old_White[p] = Start_Graf_Layout[p] ;
  373.         Old_Black[p] = Start_Graf_Layout[p] ;
  374.     }
  375.  
  376.     Draw_Board_Quick (Lays[BLACK_PLAYER],Lays[WHITE_PLAYER]) ;
  377.  
  378.     if (!No_Cube) {
  379.         Draw_Double_Button () ;
  380.     }
  381. }
  382.  
  383. /***************************************************************************/
  384.  
  385. void Draw_Board_Quick (Layout_t Black, Layout_t White)
  386. /*
  387. PURPOSE: To update the board quickly, drawing only the points
  388.          which have changed.
  389. NOTES  : The loop with pb and pw: Remember that they are both two
  390.          views of the same thing.
  391. */
  392. {
  393.     short pb,pw ;
  394.     boolean Bar_Change ;
  395.  
  396.     Clear_Help_Line () ;
  397.  
  398.     /* Draw the pieces which are on points */
  399.     for (pw = 1 ; pw <= POINT24_I ; pw++) {
  400.         pb = Reverse_Index (pw) ;
  401.         if ((White[pw] != Old_White[pw]) ||
  402.             (Black[pb] != Old_Black[pb])) {
  403.             if (Black[pb] > 0) {
  404.                 Draw_Point_And_Pieces (BLACK_PLAYER,pb,Black[pb]) ;
  405.             } else if (White[pw] > 0) {
  406.                 Draw_Point_And_Pieces (WHITE_PLAYER,pw,White[pw]) ;
  407.             } else {
  408.                 Draw_Point_Triangle (WHITE_PLAYER,pw) ;
  409.             }
  410.         }
  411.     }
  412.  
  413.     /* Draw any changes on the bar */
  414.     Bar_Change = FALSE ;
  415.     if (White[BAR_I] != Old_White[BAR_I]) {
  416.         Draw_Point_And_Pieces (WHITE_PLAYER,BAR_I,White[BAR_I]) ;
  417.         Bar_Change = TRUE ;
  418.     }
  419.     if (Black[BAR_I] != Old_Black[BAR_I]) {
  420.         Draw_Point_And_Pieces (BLACK_PLAYER,BAR_I,Black[BAR_I]) ;
  421.         Bar_Change = TRUE ;
  422.     }
  423.     if (Bar_Change) {
  424.         extern int      Double_Value ;
  425.         extern Player_t Double_Possessor ;
  426.         extern boolean  No_Cube ;
  427.         if (!No_Cube) {
  428.             Draw_Double_Button () ;
  429.             Draw_Double_Cube (Double_Possessor,Double_Value) ;
  430.         }
  431.     }
  432.  
  433.     /* Draw any changes at home */
  434.     if (White[HOME_I] != Old_White[HOME_I]) {
  435.         Draw_Point_And_Pieces (WHITE_PLAYER,HOME_I,White[HOME_I]) ;
  436.     }
  437.     if (Black[HOME_I] != Old_Black[HOME_I]) {
  438.         Draw_Point_And_Pieces (BLACK_PLAYER,HOME_I,Black[HOME_I]) ;
  439.     }
  440.  
  441.     /* Remember what this display was like */
  442.     for (pw = 0 ; pw < N_PLACES ; pw++) {
  443.         Old_Black[pw] = Black[pw] ;
  444.         Old_White[pw] = White[pw] ;
  445.     }
  446.  
  447.  
  448. }
  449.  
  450. /***************************************************************************/
  451.  
  452. void Clear_Point (Player_t Player, short Point_Num)
  453. {
  454.     short A_Box [2][2] ; /* Defines box of the point */
  455.  
  456.     Get_Pbox_Coords (A_Box,Player,Point_Num) ;
  457.     Fill_Rect (A_Box[0][XI],A_Box[0][YI],
  458.                Grafs.Grid_Wide-1,
  459.                A_Box[1][YI]-A_Box[0][YI],BLACK) ;
  460. }
  461.  
  462. /***************************************************************************/
  463.  
  464. void Get_Piece_Center (short* X_Center, short* Y_Center,
  465.                        Player_t Player,
  466.                        short Point_Num, short Piece_Row,
  467.                        short Total_Pieces, short Rows_Available)
  468. /*
  469. PURPOSE: To return the graphical center of the Player piece at Piece_Row,Point_Num.
  470. */
  471. {
  472.     if (Total_Pieces <= Rows_Available) {
  473.         /* No squeezing required */
  474.         short Row,Col ;
  475.  
  476.         Get_Grid_Point  (&Col,&Row,Player,Point_Num,Piece_Row) ;
  477.         Get_Grid_Center (X_Center,Y_Center,Col,Row) ;
  478.  
  479.     } else {
  480.         /* Squeezing required to get all pieces in space available. */
  481.         short Y_Center_Start,Y_Center_End,Y_Offset ;
  482.  
  483.         Get_Piece_Center (X_Center,&Y_Center_Start,
  484.                           Player,Point_Num,0,Rows_Available,Rows_Available) ;
  485.         Get_Piece_Center (X_Center,&Y_Center_End,
  486.                           Player,Point_Num,Rows_Available-1,Rows_Available,Rows_Available) ;
  487.  
  488.         Y_Offset    = (Piece_Row*(Y_Center_End-Y_Center_Start))/(Total_Pieces-1) ;
  489.         (*Y_Center) = Y_Center_Start + Y_Offset ;
  490.     }
  491. }
  492.  
  493. /***************************************************************************/
  494.  
  495. char Show_Transits_And_Kb_Look (Transit_t* Me, Transit_t* Him,
  496.                                 Player_t Player, Speed_t Speed)
  497. /*
  498. PURPOSE: To draw the motions contained in the transits, and to look
  499.          at the keyboard.
  500. NOTES:   1) The Speed parameter tells us how fast to display the transits.
  501.          2) I have not yet thoiught of a simple way of seperating these
  502.             two functions, what with the PAUSING option.
  503. */
  504. {
  505.     char Return_Char ;
  506.  
  507.     if (kbhit() && Speed != PAUSING) {
  508.         Return_Char = (char)Get_Key () ;
  509.     } else {
  510.         Return_Char = NUL ;
  511.     }
  512.  
  513.     if (Speed == FULL_SPEED) {
  514.         return (Return_Char) ;
  515.     }
  516.  
  517.     Draw_Transits (Me, Him, Player) ;  /* Draw the paths */
  518.  
  519.     switch (Speed) {
  520.         case MED_SPEED :
  521.             /* Show transits as fast as you can */
  522.             break ;
  523.         case SLOW_SPEED :
  524.             /* Show transits slowly */
  525.             Seconds_Delay (2) ;
  526.             break ;
  527.         case PAUSING :
  528.             /* User hits a key half way through */
  529.             Print_Message (HIT_MOUSE_MSG) ;
  530.             (void)Get_User_Point_Choice (&Return_Char,BLACK_PLAYER,QUESTION_SHP) ;
  531.             Clear_Help_Line () ;
  532.             break ;
  533.  
  534.         #if DEBUG_SOURCE
  535.         default :
  536.             printf ("\nERROR in Show_Transits, Speed = %d",Speed) ;
  537.             Error_Exit ("Bad Speed in Show_Transits") ;
  538.             break ;
  539.         #endif
  540.  
  541.     }
  542.  
  543.     Draw_Transits (Me, Him, Player) ;  /* Erase the paths */
  544.     return (Return_Char) ;
  545. }
  546.  
  547. /***************************************************************************/
  548.  
  549. void Side_Text (short Row, short Col, char* String, short Color)
  550. /*
  551. PURPOSE: To draw a string at the given row-col in the side text area.
  552. NOTES  : 1) MSC uses text coords starting at 1, not 0, whereas this
  553.          function is called assuming 0,0 is the top left coord, not 1,1.
  554.          2) MSC uses row-col addressing, not pixel addressing.
  555.          3) If you print on the very last character space of the screen
  556.             MSC give you an (unwanted and unexpected) CRLF, so you have
  557.             to avoid that.
  558. */
  559. {
  560.     Row = Row + Disp_Cfg.Text_Rows - SIDE_ROWS ;
  561.     Col = Col + Disp_Cfg.Text_Cols - SIDE_COLS ;
  562.  
  563.     Graf_Text (Row,Col,String,Color) ;
  564. }
  565.  
  566. /***************************************************************************/
  567.  
  568. void Help_Text (short Col, char* String, short Color)
  569. /*
  570. PURPOSE: To draw a string at the given col in the help text area.
  571. */
  572. {
  573.     short Row ;
  574.  
  575.     Row = Disp_Cfg.Text_Rows - 1 ;
  576.     Graf_Text (Row,Col,String,Color) ;
  577. }
  578.  
  579. /***************************************************************************/
  580.  
  581. void Clear_Help_Line (void)
  582. /*
  583. PURPOSE: To clear the single line of help at the bottom of the screen.
  584. */
  585. {
  586.     Fill_Rect (Grafs.Help_X,Grafs.Help_Y,
  587.                Grafs.Help_X+Grafs.Help_Wide,
  588.                Grafs.Help_Y+Disp_Cfg.Char_High,0) ;
  589. }
  590.  
  591. /***************************************************************************/
  592.  
  593. boolean Pixel_To_Grid (short* Col, short* Row, short x, short y)
  594. /*
  595. PURPOSE: Given the pixel at x,y, set the row and col to the relevant
  596.          grid, returning FALSE if x,y is outside of the grid.
  597. */
  598. {
  599.     if ((x < Grafs.Board_X) || (x > Grafs.Board_X + Grafs.Board_Wide)) {
  600.         return (FALSE) ;
  601.     } else if ((y < Grafs.Board_Y) || (y > Grafs.Board_Y + Grafs.Board_High)) {
  602.         return (FALSE) ;
  603.     }
  604.  
  605.     x = x - Grafs.Board_X ;
  606.     y = y - Grafs.Board_Y ;
  607.  
  608.     (*Col) = x / Grafs.Grid_Wide ;
  609.     (*Row) = y / Grafs.Grid_High ;
  610.  
  611.     return (TRUE) ;
  612. }
  613.  
  614. /***************************************************************************/
  615.  
  616. short Grid_To_Point (short G_Col, short G_Row, short Player)
  617. /*
  618. PURPOSE: To return the point specified by the grid coords.
  619. NOTES:   1) We do the basic calcs assuming BLACK player and reverse
  620.          the point if it is white at the end.
  621.          2) Study the diagram at the top of this file.
  622. */
  623. {
  624.     short Point ;
  625.  
  626.     /* Do these simple cases first... */
  627.     if (G_Col == BAR_COL) {
  628.         return (BAR_I) ;
  629.     } else if (G_Col == HOME_COL) {
  630.         return (HOME_I) ;
  631.     }
  632.  
  633.     if (G_Row < (GRID_ROWS/2)) {
  634.         /* In top half of the board */
  635.         if (G_Col > 6) {
  636.             Point = G_Col - 1 ;
  637.         } else {
  638.             Point = G_Col ;
  639.         }
  640.     } else {
  641.         /* In bottom half of the board */
  642.         if (G_Col > 6) {
  643.             Point = 13 + (13 - G_Col) ;
  644.         } else {
  645.             Point = 19 + ( 6 - G_Col) ;
  646.         }
  647.     }
  648.  
  649.     if ((Point < 0) || (Point > HOME_I)) {
  650.         Error_Exit ("Point out of range") ;
  651.     }
  652.  
  653.     if (Player == BLACK_PLAYER) {
  654.         return (Point) ;
  655.     } else {
  656.         return (Reverse_Index(Point)) ;
  657.     }
  658. }
  659.  
  660. /***************************************************************************/
  661.  
  662.